use async_trait::async_trait;
use my_rust_core::security::{id_field::IdField, jwt::Role};
use std::sync::Arc;

use sea_orm::{
    ColumnTrait, Condition, DatabaseConnection, EntityTrait, QueryFilter, QuerySelect,
    RelationTrait,
};

use crate::entities;

#[async_trait]
pub trait UserRoleService: Send + Sync {
    /// Queries roles' id, authoritym title based on provided user id against specific account group.
    async fn query_full_roles(&self, account_group_id: &str, user_id: &str) -> Vec<Role>;
}

pub struct UserRoleServiceImpl {
    db: Arc<DatabaseConnection>,
}

impl UserRoleServiceImpl {
    pub fn new(db: Arc<DatabaseConnection>) -> Self {
        UserRoleServiceImpl { db }
    }
}

#[async_trait]
impl UserRoleService for UserRoleServiceImpl {
    /// Queries roles' id, authoritym title based on provided user id against specific account group.
    async fn query_full_roles(&self, account_group_id: &str, user_id: &str) -> Vec<Role> {
        let result: Vec<(String, String, String)> = entities::prelude::UserRole::find()
            .select_only()
            .columns([
                entities::role::Column::Id,
                entities::role::Column::Authority,
                entities::role::Column::Title,
            ])
            .join(
                sea_orm::JoinType::InnerJoin,
                entities::user_role::Relation::Role.def(),
            )
            .filter(
                Condition::all()
                    .add(entities::user_role::Column::AccountGroupId.eq(account_group_id))
                    .add(entities::user_role::Column::UserId.eq(user_id)),
            )
            .into_tuple()
            .all(self.db.as_ref())
            .await
            .unwrap();

        result
            .iter()
            .map(|(id, authority, title)| Role {
                id: IdField::Text(id.to_owned()),
                authority: authority.to_owned(),
                title: title.to_owned(),
            })
            .collect::<Vec<Role>>()
    }
}
